import { Adapter } from "../adapter/adapter";
import { BitMath } from "../math/math";
import { Tile_Struct } from "./tile_struct"
import { Tile_Element } from "./tile_tile";

export namespace Tile_Bank
{
    export class BankSlot
    {
        constructor(render: Adapter.IRenderAdapter, palette: BitMath.OutPalette, width: number, height: number)
        {
            this.backTexture = render.CreateWriteableTexture(palette, width, height);
        }
        public backTexture: Adapter.ITexture_Writeable;
        public tilePutX: number = 0;
        public tilePutY: number = 0;
        public LineHeight: number = 0;
    }
    const defaultslottextsize: number = 1024;

    export class Bank
    {

        //1024的贴图可以放得下 16384 个Tile（一个Tile8x8）,一万多，足够浪费了
        //注：Nes 才支持512个Tile

        //我们只需要把文字分到一个单独的Bank里
        //文字默认用的12x12，一张1024贴图能放 7,225‬ 个，这个数量比区位码保存的汉字多一些，这时候，我们只需要启动一个动态字模机制，
        //绝对用不到全部7225个文字,也就是放不满
        constructor(palette: BitMath.OutPalette, render: Adapter.IRenderAdapter)
        {
            this.render = render;
            this.palette = palette;


            this.slots = [];
            this.namedTile = {};
            this.namedTileData = {};

            this.CreateSlot(defaultslottextsize, defaultslottextsize);

        }
        render: Adapter.IRenderAdapter
        slots: BankSlot[];
        CreateSlot(width: number, height: number): void
        {
            let slot = new BankSlot(this.render, this.palette, width, height);
            slot.tilePutX = 0;
            slot.tilePutY = 0;
            slot.LineHeight = 0;

            this.slots.push(slot);

        }
        private _bankID: number = 0;
        private _tileID: number = 0;
        public get bankID()
        {
            return this._bankID;
        }
        public palette: BitMath.OutPalette;

        namedTile: { [id: string]: Tile_Element.RenderTile }

        namedTileData: { [id: string]: Tile_Struct.TileData };

        private _CreateTile(name: string, data: Tile_Struct.TileData, palettedata: Tile_Struct.TilePaletteData | null): Tile_Element.RenderTile
        {
            let rt = this.namedTile[name];
            if (rt != undefined)
                return rt;

            var lastslot = this.slots[this.slots.length - 1];

            //摆不下，换行
            if (lastslot.tilePutX + data.pixelwidth > lastslot.backTexture.width)
            {
                lastslot.tilePutY += lastslot.LineHeight;
                lastslot.tilePutX = 0;
                lastslot.LineHeight = data.pixelheight;
            }
            //换行也摆不下，新建slot
            if (lastslot.tilePutY + data.pixelheight > lastslot.backTexture.height)
            {
                this.CreateSlot(defaultslottextsize, defaultslottextsize);
                lastslot = this.slots[this.slots.length - 1];
            }


            var rect: BitMath.Rect = { x: lastslot.tilePutX, y: lastslot.tilePutY, w: data.pixelwidth, h: data.pixelheight };

            lastslot.backTexture.BeginWrite(lastslot.tilePutX, lastslot.tilePutY, data.pixelwidth, data.pixelheight);
            for (var y = 0; y < data.pixelheight; y++)
            {
                var line = data.GetLineWithPalette(y, palettedata);
                lastslot.backTexture.Write8bitBlock(0, y, line, data.pixelwidth);
            }
            lastslot.backTexture.EndWrite();
            //lastslot.backTexture.putImageData(imgData, lastslot.tilePutX, lastslot.tilePutY);

            // int lockresult = SDL.SDL_LockTexture(lastslot.sdlTexture, ref rect, out IntPtr pixels, out int pitch);
            // unsafe
            // {
            //   byte * pixeldata = (byte *)pixels;
            //   for (var y = 0; y < data.pixelheight; y++)
            //   {
            //     var line = data.GetLineWithPalette(y, palettedata);
            //     for (var x = 0; x < data.pixelwidth; x++)
            //     {

            //       var color = this.palette[line[x]];
            //       pixeldata[y * pitch + x * 4 + 0] = color.b;
            //       pixeldata[y * pitch + x * 4 + 1] = color.g;
            //       pixeldata[y * pitch + x * 4 + 2] = color.r;
            //       pixeldata[y * pitch + x * 4 + 3] = color.a; // pp red

            //     }
            //   }
            // }

            //SDL.SDL_UnlockTexture(lastslot.sdlTexture);

            lastslot.LineHeight = Math.max(lastslot.LineHeight, data.pixelheight);
            lastslot.tilePutX += data.pixelwidth;

            var tile = new Tile_Element.RenderTile(this, this._tileID, lastslot.backTexture, rect);
            // tile.bank = this;
            // tile.tex = lastslot.sdlTexture;
            // tile.srcrect = rect;
            // tile.tileID = namedTile.Count;
            this.namedTile[name] = tile;
            this._tileID++;
            return tile;
        }

        public CreateTile(name: string, data: Tile_Struct.TileData): Tile_Element.RenderTile
        {
            return this._CreateTile(name, data, null);
        }
        //也可以先RegData,这样不会生成，GetTileByName时如果找不到，会尝试创建
        public RegTileData(name: string, data: Tile_Struct.TileData): void
        {
            this.namedTileData[name] = data;
        }
        public GetTileData(name: string): Tile_Struct.TileData | null
        {
            var data = this.namedTileData[name];
            if (data == undefined)
                return null;
            else
                return data;

        }
        //创建一个Tile的不同调色板副本
        public CreateTile2PFromRegTile(name2p: string, srcTileName: string, palettedata: Tile_Struct.TilePaletteData): Tile_Element.RenderTile
        {
            if (palettedata == null)
            {
                throw new Error("create 2p tile must have a pallettedata");
            }
            var tiledata = this.namedTileData[srcTileName];
            return this._CreateTile(name2p, tiledata, palettedata);
        }

        public GetTileByName(name: string): Tile_Element.RenderTile | null
        {
            var tile = this.namedTile[name];
            if (tile != undefined)
                return tile;


            var data = this.namedTileData[name];
            if (data != undefined)
            {
                return this.CreateTile(name, data);
            }
            return null;
        }
    }
}